<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>

    <link rel="stylesheet" type="text/css" 
      href="/assets/css/straybirds.css" media="screen" />
    <link rel="stylesheet" type="text/css" 
      href="/assets/css/pygments.css" media="screen" />

    <!-- MathJax Section Start -->

    <script type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
    </script>
    <script>
        MathJax.Hub.Config({
              tex2jax: {
              skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
              }
        });
        MathJax.Hub.Queue(function() {
            var all = MathJax.Hub.getAllJax(), i;
            for(i=0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

    <!-- MathJax Section End -->

    <!-- Google Analytics Start-->
    <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-48100787-1', 'minixalpha.github.io');
  ga('send', 'pageview');

</script>

    <!-- Google Analytics End -->

    <title>web.py 源代码分析之 web.test.application.test_UppercaseMethods</title>
  </head>

  <body>
    <div class="container">
      <header>
        <div class="container">
          <h1>
              <a href="/" title="Home Page"> 潇湘夜雨 </a>
          <span class="github-src">
            <a href ="https://github.com/minixalpha/minixalpha.github.io"
               target="_blank"
               title="Fork me on GitHub">
              <img src="/assets/images/GitHub-Mark-Light-32px.png" alt="">
            </a>
          </span>
          </h1>
        </div>
      </header>

      <aside id="left-side">
        <h2> 分类 </h2>
  <ul class="category-list">
      
            
                <li style="background-color: #444">
                <a href="/categories/源代码阅读"> 源代码阅读 (20) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/设计模式"> 设计模式 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/科研"> 科研 (6) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/思想"> 思想 (2) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/技术"> 技术 (18) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/工具"> 工具 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/虚拟机"> 虚拟机 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/java"> java (11) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/c语言"> c语言 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/读书"> 读书 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/操作系统"> 操作系统 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/英语"> 英语 (10) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/计算机系统"> 计算机系统 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/生活"> 生活 (1) </a>
                </li>
            
      
  </ul>

      </aside>

      <aside id="right-side">
        <h2> 归档 </h2>
  <ul class="archive-list">
    
    
    
        
        
        
        
            
            <li>
                <a href="/2014/08">
                    2014-08 (1)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/07">
                    2014-07 (5)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/05">
                    2014-05 (12)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/04">
                    2014-04 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/03">
                    2014-03 (11)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/02">
                    2014-02 (6)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/01">
                    2014-01 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/11">
                    2013-11 (10)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/10">
                    2013-10 (3)
                </a>
            </li>

        
        
    
        
        
        
        
            
            <li>
                <a href="/2010/09">
                    2010-09 (1)
                </a>
            </li>

        
        
    
  </ul>

      </aside>

      <article>

<h1>分模块测试</h1>

<h2>application.py</h2>

<p>对 application.py 的测试，调用命令：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">python test/application.py
</code></pre></div>
<h3>test_UppercaseMethods(self)</h3>

<p>这个函数源代码是：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">testUppercaseMethods</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="n">urls</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="s">&quot;hello&quot;</span><span class="p">)</span>
    <span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">locals</span><span class="p">())</span>
    <span class="k">class</span> <span class="nc">hello</span><span class="p">:</span>
        <span class="k">def</span> <span class="nf">GET</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="s">&quot;hello&quot;</span>
        <span class="k">def</span> <span class="nf">internal</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="s">&quot;secret&quot;</span>

    <span class="n">response</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;internal&#39;</span><span class="p">)</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status</span><span class="p">,</span> <span class="s">&#39;405 Method Not Allowed&#39;</span><span class="p">)</span>
</code></pre></div>
<p>这个函数似乎是在测试 <code>request</code> 请求的方法不正确时，<code>application</code>
的反应。</p>

<p>我们打印一下 <code>response</code> 的值，发现内容是这样的：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&lt;Storage {&#39;status&#39;: &#39;405 Method Not Allowed&#39;, 
&#39;headers&#39;: {&#39;Content-Type&#39;: &#39;text/html&#39;, 
&#39;Allow&#39;: &#39;GET, HEAD, POST, PUT, DELETE&#39;}, 
&#39;header_items&#39;: [(&#39;Content-Type&#39;, &#39;text/html&#39;), 
(&#39;Allow&#39;, &#39;GET, HEAD, POST, PUT, DELETE&#39;)], &#39;data&#39;: &#39;None&#39;}&gt;
</code></pre></div>
<p>从这里可以看出允许的方法：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&#39;Allow&#39;: &#39;GET, HEAD, POST, PUT, DELETE&#39;
</code></pre></div>
<p><code>response.status</code> 最终值为：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&#39;status&#39;: &#39;405 Method Not Allowed&#39;,
</code></pre></div>
<p>我们再一次深入 <code>web.application.request</code>, 看一看具体实现。</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python">    <span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">localpart</span><span class="o">=</span><span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;GET&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
                <span class="n">host</span><span class="o">=</span><span class="s">&quot;0.0.0.0:8080&quot;</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">https</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>

        <span class="o">...</span>

        <span class="n">env</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
            <span class="n">env</span><span class="p">,</span> 
            <span class="n">HTTP_HOST</span><span class="o">=</span><span class="n">host</span><span class="p">,</span> 
            <span class="n">REQUEST_METHOD</span><span class="o">=</span><span class="n">method</span><span class="p">,</span> 
            <span class="n">PATH_INFO</span><span class="o">=</span><span class="n">path</span><span class="p">,</span> 
            <span class="n">QUERY_STRING</span><span class="o">=</span><span class="n">query</span><span class="p">,</span> 
            <span class="n">HTTPS</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">https</span><span class="p">)</span>
            <span class="p">)</span>

        <span class="o">...</span>

        <span class="n">response</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">storage</span><span class="p">()</span>
        <span class="k">def</span> <span class="nf">start_response</span><span class="p">(</span><span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="p">):</span>
            <span class="n">response</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="n">status</span>
            <span class="n">response</span><span class="o">.</span><span class="n">headers</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">headers</span><span class="p">)</span>
            <span class="n">response</span><span class="o">.</span><span class="n">header_items</span> <span class="o">=</span> <span class="n">headers</span>

        <span class="n">response</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">wsgifunc</span><span class="p">()(</span><span class="n">env</span><span class="p">,</span> <span class="n">start_response</span><span class="p">))</span>

        <span class="k">return</span> <span class="n">response</span>
</code></pre></div>
<p>我们只保留了关键代码，可以看出，method 首先被设置在了 <code>env</code> 中，然后，
通过 </p>
<div class="highlight"><pre><code class="python language-python" data-lang="python">    <span class="bp">self</span><span class="o">.</span><span class="n">wsgifunc</span><span class="p">()(</span><span class="n">env</span><span class="p">,</span> <span class="n">start_response</span><span class="p">))</span>
</code></pre></div>
<p><code>start_response</code> 被 <code>wsgifunc()</code> 返回的函数调用，<code>response</code> 的值被设置。 如果阅读了前面推荐的几篇关于 <code>WSGI</code> 的文章，对这里的 <code>self.wsgifunc()</code> 和 <code>start_response</code>应该不会感觉到陌生。</p>

<p>好，我们继续深入 <code>web.application.wsgifunc()</code></p>
<div class="highlight"><pre><code class="python language-python" data-lang="python">    <span class="k">def</span> <span class="nf">wsgifunc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">middleware</span><span class="p">):</span>

        <span class="o">...</span>

        <span class="k">def</span> <span class="nf">wsgi</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">start_resp</span><span class="p">):</span>
            <span class="c"># clear threadlocal to avoid inteference of previous requests</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_cleanup</span><span class="p">()</span>

            <span class="bp">self</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="c"># allow uppercase methods only</span>
                <span class="k">if</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">method</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span> <span class="o">!=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">method</span><span class="p">:</span>
                    <span class="k">raise</span> <span class="n">web</span><span class="o">.</span><span class="n">nomethod</span><span class="p">()</span>

                <span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">handle_with_processors</span><span class="p">()</span>
                <span class="k">if</span> <span class="n">is_generator</span><span class="p">(</span><span class="n">result</span><span class="p">):</span>
                    <span class="n">result</span> <span class="o">=</span> <span class="n">peep</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">result</span> <span class="o">=</span> <span class="p">[</span><span class="n">result</span><span class="p">]</span>
            <span class="k">except</span> <span class="n">web</span><span class="o">.</span><span class="n">HTTPError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
                <span class="n">result</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="o">.</span><span class="n">data</span><span class="p">]</span>


            <span class="n">result</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">safestr</span><span class="p">(</span><span class="nb">iter</span><span class="p">(</span><span class="n">result</span><span class="p">))</span>

            <span class="n">status</span><span class="p">,</span> <span class="n">headers</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">status</span><span class="p">,</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">headers</span>
            <span class="n">start_resp</span><span class="p">(</span><span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>

            <span class="k">def</span> <span class="nf">cleanup</span><span class="p">():</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_cleanup</span><span class="p">()</span>
                <span class="k">yield</span> <span class="s">&#39;&#39;</span> <span class="c"># force this function to be a generator</span>

            <span class="k">return</span> <span class="n">itertools</span><span class="o">.</span><span class="n">chain</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">cleanup</span><span class="p">())</span>

        <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">middleware</span><span class="p">:</span> 
            <span class="n">wsgi</span> <span class="o">=</span> <span class="n">m</span><span class="p">(</span><span class="n">wsgi</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">wsgi</span>
</code></pre></div>
<p>从上述代码可以看出，返回的函数就是 <code>wsgi</code>, <code>wsgi</code> 在返回前，可能
会使用 <code>middleware</code> 进行一层一层的包装。不过这里，我们只看 <code>wsgi</code>
的代码就可以了。</p>

<p>关键的两行在：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="n">status</span><span class="p">,</span> <span class="n">headers</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">status</span><span class="p">,</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">headers</span>
<span class="n">start_resp</span><span class="p">(</span><span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
</code></pre></div>
<p>这里，<code>web.application.requests.start_response</code> 函数 被调用，并设置好
<code>status</code> 和 <code>headers</code>，二者的值从 <code>web.ctx</code> 中取得。所以，下一部，我们
关心 <code>web.ctx</code> 值的来源。因为 <code>method</code> 的信息在 <code>env</code> 中，所以 
<code>web.ctx</code> 的值一定会受 <code>env</code> 的影响，所以在 <code>wsgi</code> 中要找到 <code>env</code>是如何
被使用的。</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="bp">self</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">env</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
    <span class="c"># allow uppercase methods only</span>
    <span class="k">if</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">method</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span> <span class="o">!=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">method</span><span class="p">:</span>
        <span class="k">raise</span> <span class="n">web</span><span class="o">.</span><span class="n">nomethod</span><span class="p">()</span>
</code></pre></div>
<p>我们猜想 <code>self.load(env)</code> 对 <code>web.ctx</code> 进行了设置，然后后面的 <code>try</code>
对 <code>web.ctx</code> 检查，这里对 <code>upper</code>的检查，让我们想到了，原来一开始的
<code>testUppercaseMethods</code> 是在测试 <code>method</code> 名字是不是全是大写。。。</p>

<p>于是在 <code>raise web.nomethod()</code> 前加一个 <code>print</code> ，测试一下是不是执行到
了这里，发现还真是。那么我们再深入 <code>load</code> ，看看如何根据 <code>env</code> 设置
<code>web.ctx</code>。</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">env</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Initializes ctx using env.&quot;&quot;&quot;</span>
    <span class="n">ctx</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span>
    <span class="n">ctx</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
    <span class="n">ctx</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s">&#39;200 OK&#39;</span>

    <span class="o">...</span>

    <span class="n">ctx</span><span class="o">.</span><span class="n">method</span> <span class="o">=</span> <span class="n">env</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;REQUEST_METHOD&#39;</span><span class="p">)</span>

    <span class="o">...</span>
</code></pre></div>
<p><code>load</code> 函数会根据 <code>env</code> 设置 <code>web.ctx</code> ，但是只是简单赋值，没有对
<code>method</code> 方法的检查。于是，我明白了，原来是在 <code>raise web.nomethod()</code>中对
<code>status</code> 进行了设置。</p>

<p>在 <code>raise</code> 之前打印 <code>web.ctx.status</code> 的值，果然是 <code>200 OK</code>。那我们再进入
<code>web.nomethod</code> 看看吧。</p>

<p>这个函数在 <code>webapi.py</code> 中，进入文件一看，果然是对许多状态的定义。
找到 <code>nomethod</code> ，发现指向 <code>NoMethod</code>，下面看 <code>NoMethod</code>:</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">class</span> <span class="nc">NoMethod</span><span class="p">(</span><span class="n">HTTPError</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;A `405 Method Not Allowed` error.&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">cls</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="n">status</span> <span class="o">=</span> <span class="s">&#39;405 Method Not Allowed&#39;</span>
        <span class="n">headers</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="n">headers</span><span class="p">[</span><span class="s">&#39;Content-Type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;text/html&#39;</span>

        <span class="n">methods</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;GET&#39;</span><span class="p">,</span> <span class="s">&#39;HEAD&#39;</span><span class="p">,</span> <span class="s">&#39;POST&#39;</span><span class="p">,</span> <span class="s">&#39;PUT&#39;</span><span class="p">,</span> <span class="s">&#39;DELETE&#39;</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">cls</span><span class="p">:</span>
            <span class="n">methods</span> <span class="o">=</span> <span class="p">[</span><span class="n">method</span> <span class="k">for</span> <span class="n">method</span> <span class="ow">in</span> <span class="n">methods</span> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">method</span><span class="p">)]</span>

        <span class="n">headers</span><span class="p">[</span><span class="s">&#39;Allow&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">methods</span><span class="p">)</span>
        <span class="n">data</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="n">HTTPError</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
</code></pre></div>
<p>发现还真是对错误号 <code>405</code> 的处理。 设置好status, 最终的处理
发给了 <code>HTTPError</code>，所以我们再进入 <code>HTTPError</code>。</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">class</span> <span class="nc">HTTPError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="p">{},</span> <span class="n">data</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">):</span>
        <span class="n">ctx</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="n">status</span>
        <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">headers</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">header</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span>
        <span class="ne">Exception</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">status</span><span class="p">)</span>
</code></pre></div>
<p>这里终于发现了对 <code>ctx.status</code> 的设置。这就是在这里我们知道了下面这两
行关键代码的最终来源。</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="n">status</span><span class="p">,</span> <span class="n">headers</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">status</span><span class="p">,</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">headers</span>
<span class="n">start_resp</span><span class="p">(</span><span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
</code></pre></div>
<p>前者设置 <code>status</code> 和 <code>headers</code>，后者调用 <code>requests</code> 函数中的 <code>start_response</code> 对
 <code>response</code> 的状态进行了设置。最后返回给最一开始 <code>testUppercaseMethods</code> 中的 
 <code>response</code>。</p>


      </article>

      <div class="comments">
        
          <div id="disqus_thread"></div>
 <script type="text/javascript">
     /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
     var disqus_shortname = 'minixalpha'; // required: replace example with your forum shortname

     /* * * DON'T EDIT BELOW THIS LINE * * */
     (function() {
         var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
         dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
         (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
     })();
 </script>
 <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
    

        
      </div>


      <footer>
        Copyright (c) minixalpha 2014
      </footer>

    </div>
  </body>
</html>
